1 /*
2 Copyright: Marcelo S. N. Mancini, 2018 - 2021
3 License:   [https://opensource.org/licenses/MIT|MIT License].
4 Authors: Marcelo S. N. Mancini
5 
6 	Copyright Marcelo S. N. Mancini 2018 - 2021.
7 Distributed under the MIT Software License.
8    (See accompanying file LICENSE.txt or copy at
9 	https://opensource.org/licenses/MIT)
10 */
11 
12 module hip.event.handlers.keyboard;
13 
14 import hip.event.handlers.keyboard_layout;
15 public import hip.event.handlers.button;
16 public import hip.api.input.keyboard;
17 
18 import hip.util.data_structures;
19 import hip.error.handler;
20 import hip.util.time, hip.util.array;
21 
22 char toUppercase(char a)
23 {
24     ubyte charV = ubyte(a);
25     if(charV >= HipKey.A+32 && charV <= HipKey.Z+32)
26         return cast(char)(charV-32);
27     return a;
28 }
29 
30 
31 
32 
33 /** 
34  *  This class controls callbacks related to keyboard buttons state, as its downtime, uptime,
35  *  its current state, modifier key states and callbacks assigned to specific keys.
36  *
37  *  Controls what text has been typed in the current frame, useful for Label or Text objects.
38  */
39 class KeyboardHandler : IHipKeyboard
40 {
41     private __gshared ubyte[256] pressedKeys;
42     private __gshared HipButtonMetadata[256] metadatas;
43     private __gshared string frameText;
44 
45     private __gshared bool altPressed;
46     private __gshared bool shiftPressed;
47     private __gshared bool ctrlPressed;
48     private __gshared float keyRepeatDelay = 0.5;
49 
50     this()
51     {
52         if(metadatas[0] is null)
53         {
54             for(int i = 0; i < 256; i++)
55                 metadatas[i] = new HipButtonMetadata(i);
56             pressedKeys[] = 0;
57         }
58     }
59     
60 
61     /**
62     * Takes care of the pressed keys array
63     */
64     private void setPressed(HipKey key, bool press)
65     {
66         ubyte Key = cast(ubyte)key;
67         metadatas[Key].setPressed(press);
68         if(press)
69         {
70             if(pressedKeys.indexOf(Key) == -1)
71                 pressedKeys[pressedKeys.indexOf(0)] = Key; //Assign to null index a key
72         }
73         else
74         {
75             const int index = pressedKeys.indexOf(0); //Get last index
76             const int upIndex = pressedKeys.indexOf(Key);
77             if(index > 1)
78             {
79                 swapAt(pressedKeys, index - 1, upIndex);//Swaps the current key with the last valid key
80                 pressedKeys[index - 1] = 0;
81             }
82             else pressedKeys[0] = 0;
83         }
84         switch(key)
85         {
86             case HipKey.ALT:
87                 altPressed = press;
88                 break;
89             case HipKey.CTRL:
90                 ctrlPressed = press;
91                 break;
92             case HipKey.SHIFT:
93                 shiftPressed = press;
94                 break;
95             default:
96                 break;
97         }
98 
99     }
100 
101     void handleKeyUp(HipKey key)
102     {
103         setPressed(key, false);
104     }
105     AHipButtonMetadata getMetadata(char key) const {return metadatas[key];}
106 
107     bool isKeyPressed(char key){return metadatas[key]._isPressed;}
108     bool isKeyJustPressed(char key){return metadatas[key].isJustPressed;}
109     bool isKeyJustReleased(char key){return metadatas[key].isJustReleased;}
110     float getKeyDownTime(char key){return metadatas[key].getDownTimeDuration();}
111     float getKeyUpTime(char key){return metadatas[key].getUpTimeDuration();}
112 
113     
114     /**
115     *   Updates the metadata
116     */
117     void handleKeyDown(HipKey key)
118     {
119         setPressed(key, true);
120         // import hip.console.log;
121         // logln("Set pressed the key ", key);
122     }
123     
124     static string getInputText(KeyboardLayout layout)
125     {
126         KeyboardLayout.KeyState state = KeyboardLayout.KeyState.NONE;
127         if(altPressed)
128             state|= KeyboardLayout.KeyState.ALT;
129         if(shiftPressed)
130             state|= KeyboardLayout.KeyState.SHIFT;
131         if(ctrlPressed)
132             state|= KeyboardLayout.KeyState.CTRL;
133         string ret = "";
134         int i = 0;
135         while(pressedKeys[i] != 0)
136         {
137             const float pressTime = metadatas[pressedKeys[i]].getDownTimeDuration();
138             if(pressTime >= keyRepeatDelay || metadatas[pressedKeys[i]]._isNewState)
139                 ret~= layout.getKey(toUppercase(cast(char)pressedKeys[i]), state);
140             i++;
141         }
142         return ret;
143     }
144 
145     void update()
146     {
147     }
148 
149     void postUpdate()
150     {
151         for(int i = 0; i < metadatas.length; i++)
152             metadatas[i]._isNewState = false;
153         frameText = "";
154     }
155 
156 }